#!/bin/sh

gen_ca_conf(){
            # config
        echo "
[INFO] gen ca conf"

        cat > "${rootca_conf}" <<EOF
# OpenSSL root CA configuration file.

[ ca ]
# '''man ca'''
default_ca = CA_default
prompt = no

[ CA_default ]
# Directory and file locations.
dir               = $(realpath "${root_dir}/ca")
certs             = \$dir/certs
crl_dir           = \$dir/crl
new_certs_dir     = \$dir/newcerts
database          = \$dir/index.txt
serial            = \$dir/serial
RANDFILE          = \$dir/private/.rand

# The root key and root certificate.
private_key       = \$dir/private/ca.key.pem
certificate       = \$dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber         = \$dir/crlnumber
crl               = \$dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 375
preserve          = no
policy            = policy_loose

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# match | optional | supplied ;  ??supplied ??
# See the POLICY FORMAT section of '''man ca'''.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the '''ca''' man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
# Options for the '''req''' tool ('''man req''').
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only

# SHA-1 is deprecated, so use SHA-2 instead.
default_md          = sha256

# Extension to add when the -x509 option is used.
x509_extensions     = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

# Optionally, specify some defaults.
countryName_default             = SS
stateOrProvinceName_default     = Earth
localityName_default            = Sky
0.organizationName_default      = SmallGroupX
organizationalUnitName_default  = 
emailAddress_default            = 

[ v3_ca ]
# Extensions for a typical CA ('''man x509v3_config''').
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA ('''man x509v3_config''').
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ usr_cert ]
# Extensions for client certificates ('''man x509v3_config''').
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "OpenSSL Generated Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[ server_cert ]
# Extensions for server certificates ('''man x509v3_config''').
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ crl_ext ]
# Extension for CRLs ('''man x509v3_config''').
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates ('''man ocsp''').
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

EOF

}

init_CA(){
    
    # Create the directory structure. 
    #The index.txt and serial files act as a flat file database to keep track of signed certificates.

    echo "
    [INFO] init CA ..."

    if [ ! -e "${root_dir}/ca" ];then
        mkdir "${root_dir}/ca"
        (
            cd "${root_dir}/ca"
            mkdir certs crl newcerts private csr
            chmod 700 private
            touch index.txt
            echo 1000 > serial
        )
    fi

    # key
    ## no need password
    echo "
    [INFO] gen ca key"
    if [ ! -e "${rootca_key}" ];then
        openssl genrsa -out "${rootca_key}" 4096
        chmod 400 "${rootca_key}"
    fi

    ## need password
    ### openssl genrsa -aes256 -out private/ca.key.pem 4096

    echo ""
    ## ca_cert
    gen_ca_conf

    echo "
    [INFO] gen ca crt"
    openssl req -batch -config "${rootca_conf}" \
        -new -x509 -days $DAYS -sha256 \
        -key "${rootca_key}" \
        -extensions v3_ca \
        -out "${rootca_crt}"

    date > "${root_dir}/ca/CA_IS_INITED"
}



cert_sign(){
    echo "
    [INFO]  sign cert for server"
    # $1= .csr , $2= san , $3 = .crt
    out_crt="${root_dir}/ca/certs/$(basename "$3")"
    tmpf="/tmp/cert_config.tmp"
    touch "$tmpf"
    cat "${rootca_conf}" > $tmpf
    cat "$2" >> $tmpf
    openssl ca -batch -config $tmpf -extensions server_san_cert \
      -days $DAYS -notext -md sha256 \
      -in "$1" \
      -out "$out_crt"
    
    if [ -e "$out_crt" ];then
        cp "$out_crt" "$3"
    else
        echo "[Err] gen crt error : $out_crt "
        echo "       maybe commonName is already in use. if so this error could be ignore."
        exit 1   
    fi
}


DAYS=3650
root_dir="/data"

## dir :: certs crl newcerts private
rootca_conf="${root_dir}/ca/rootca.conf"
req_conf="/tmp/cert_req_config.tmp"
touch "$req_conf"
pem_crt="certs/ca.cert.pem"
rootca_key="${root_dir}/ca/private/ca.key.pem"
rootca_crt="${root_dir}/ca/$pem_crt"



##########################
printHelp(){
    echo "  usage : "
    echo "      $0 init"
    echo "      $0 sign"
    echo "      $0 <csr> <san> <crt>"
    exit 1
}

if [ -z "$1" ];then
    printHelp
fi

echo "
[-] init ca"
if [ -e "${root_dir}/ca/CA_IS_INITED" ];then
    :
else
    (
        cd "$root_dir"
        [ -h "${root_dir}/root_ca.crt.pem" ] && rm "${root_dir}/root_ca.crt.pem"
        ln -s "ca/$pem_crt" "${root_dir}/root_ca.crt.pem"
        init_CA
    )
fi


echo "
[-] cert sign pre"
#  N?="`cat "${root_dir}/serial"`"
## N.conf from ssl_req.sh
if [ "$1" == "sign" ];then
    commonName="$2"
    if [ -e "${root_dir}/N.conf" ];then
        N="$(cat "${root_dir}/N.conf")"
        server_csr="${root_dir}/$commonName.$N.csr.pem"
        san_conf="${root_dir}/$commonName.$N.san.conf"
        server_crt="${root_dir}/$commonName.$N.crt.pem"
    else
        echo "[E] file not exist : N.conf "
        exit 1
    fi
else
    if [ -z "$3" ];then
        printHelp
    fi

    server_csr="$1"
    san_conf="$2"
    server_crt="$3"
fi

echo "
[-] ca sign"
cert_sign "$server_csr" "$san_conf" "$server_crt"

echo "*** *** 
"


